﻿_package("alz.mui");

_import("alz.core.EventBase");
_import("alz.mui.Component");
_import("alz.mui.TipBox");
_import("alz.mui.ScrollBar");

/**
 * 滚动视图组件
 */
_class("ScrollView", Component, function(){
	this._init = function(){
		_super._init.call(this);
		this._scrollbar = null;  //滚动条{ScrollBar}
		this._scroller = null;  //内容元素
		this._threshold = 10;
		this._min = 0;
		this._max = 0;
		this._viewportH = 0;  //视口高度
		this._scrollerH = 0;  //内容实际高度
		this._top = 0;   //内容相对于视口区的Y坐标
		this._offY = 0;  //移动中的偏移量
		this._pageY = 0; //每次移动时，触点在元素上最后的位置
		this._t0 = 0;    //开始滚动时间
		this._moveData = null;  //单次的滚动数据
		this._v = 0;
		this._enabled = true;
		//this._oldT = "";
		this._list = null;
	};
	this.bind = function(obj, conf){
		this.setParent(conf.parent);
		if(conf.id){
			this.setId(conf.id);
		}
		this.init(obj);
		if(conf.scrollmode == "normal"){
			this.addListener(this, "scrollEnd", this, "onDefaultScrollEnd");
		}
	};
	this.init = function(obj){
		_super.init.apply(this, arguments);
		this._scroller = this._self.childNodes[0];
		/*
		this._self.style.position = "relative";
		this._self.style.overflow = "hidden";
		this._scroller.style.position = "absolute";
		*/
		this._scrollbar = new ScrollBar();
		this._scrollbar.create(this);
		this.addListener(this._self, "touchstart", this, "onTouchStart");
		this.addListener(this._self, "touchmove", this, "onTouchMove");
		this.addListener(this._self, "touchend", this, "onTouchEnd");
	};
	this.reset = function(){
		this.setTop(0);
		this.setOffY(0);
	};
	this.dispose = function(){
		this._list = null;
		this._scrollbar.dispose();
		this._scrollbar = null;
		this._scroller = null;
		_super.dispose.apply(this);
	};
	this.setList = function(v){
		this._list = v;
	};
	this.setDisabled = function(v){
		_super.setDisabled.apply(this, arguments);
		if(v){
			this.hideScrollbar();
		}
	};
	this.showScrollbar = function(){
		this._scrollbar.setOpacity(1);
	};
	this.hideScrollbar = function(){
		this._scrollbar.setOpacity(0);
	};
	this.getViewportH = function(){
		return this._viewportH;
	};
	this._getScrollerH = function(){
		return this._scroller.offsetHeight;
	};
	this.getScrollerH = function(){
		return this._scrollerH;
	};
	this.setTop = function(v){
		this._top = v;
		//this._scroller.style.webkitTransform = "translate3d(0px, " + v + "px, 0px)";
		this._scroller.style.top = Math.round(v) + "px";
		this._scrollbar.setTop(this._viewportH * (-v / this._scrollerH));
	};
	this.getOffY = function(){
		return this._offY;
	};
	this.setOffY = function(v){
		this._offY = v;
	};
	this.setEnabled = function(v){
		this._enabled = v;
		/*
		if(this._self){
			if(v){
				this._scroller.style.webkitTransform = this._oldT;
				this._oldT = "";
			}else{
				this._oldT = this._scroller.style.webkitTransform;
				this._scroller.style.webkitTransform = "";
			}
		}
		*/
	};
	this.onTouchStart = function(ev){
		this.fireEvent("scrollstart", ev);
		//ev.stopPropagation();
	};
	this.onTouchMove = function(ev){
		this.fireEvent("scroll", ev);
	};
	this.onTouchEnd = function(ev){
		this.fireEvent("scrollend", ev);
	};
	this.onScrollStart = function(ev){
		if(this._disabled) return;
		if(this._intervalID != 0){
			window.clearInterval(this._intervalID);
			this._intervalID = 0;
		}
		this._viewportH = this._self.clientHeight;
		this._scrollerH = this._getScrollerH();
		this._min = this._viewportH - this._scrollerH;
		this._max = 0;
		//this.dump("start0");
		this._scrollbar.setHeight(this._viewportH * (this._viewportH / this._scrollerH));
		this._t0 = new Date().getTime();
		this._moveData = [];
		var touches = ev.changedTouches;
		var py = touches && touches.length == 1 ? touches[0].pageY : ev.pageY;
		this._moveData.push({"t": 0, "s": py});
		this._pageY = py - this._offY;
		this.showScrollbar();
		//this.dump("start1");
	};
	this.onScroll = function(ev){
		if(this._disabled) return;
		//this.dump("move0");
		var touches = ev.changedTouches;
		var py = touches && touches.length == 1 ? touches[0].pageY : ev.pageY;
		if(!this._moveData){
			this._moveData = [];
		}
		this._moveData.push({"t": new Date().getTime() - this._t0, "s": py});
		this._offY = py - this._pageY;
		var ds = this._moveData[this._moveData.length - 1].s - this._moveData[0].s;
		if(-this._threshold < ds && ds < this._threshold){
			return true;  //未超过滚动最小阀值
		}
		var sign = ds >= this._threshold ? 1 : -1;
		if(sign == 1 && this._offY >= this._max){  //向下移动，超出范围限制
			var y = Math.round(this._offY * 0.25);  //按比例减小滚动幅度
			this.setOffY(y);
			this.setTop(y);
		}else if(sign == -1 && this._offY <= this._min){  //向上移动，超出范围限制
			var y = this._min - Math.round((this._min - this._offY) * 0.25);  //按比例减小滚动幅度
			this.setOffY(y);
			this.setTop(y);
		}else{
			this.setTop(this._offY);
		}
		this.dispatchEvent(new EventBase("scrollMove"));
		//this.dump("move1");
	};
	this.onScrollEnd = function(ev){
		if(this._disabled) return;
		//this.dump("end0");
		var touches = ev.changedTouches;
		var py = touches && touches.length == 1 ? touches[0].pageY : ev.pageY;
		this._moveData.push({"t": new Date().getTime() - this._t0, "s": py});
		//this.hideScrollbar();
		//this.dump("end1");
		//this.scrollToPage();
		this.dispatchEvent(new EventBase("scrollEnd"));
	};
	this._removeAllItemFromArray = function(arr, item){
		var temp = [];
		for(var i = 0, len = arr.length; i < len; i++){
			var v = arr[i];
			if(v !== item && !isNaN(v)){
				temp.push(v);
			}
		}
		return temp;
	};
	this._scrollAnimation = function(){
		var offY = this.getOffY(), flag = false;
		if(offY <= this._min + this._v * 100){
			offY = this._min;
			this.animate(this._scroller, "top:" + Math.round(offY) + "px", 200, "", this, function(){
				this.setOffY(offY);
				this.setTop(offY);
			});
			flag = true;
		}else if(offY >= this._max + this._v * 100){
			offY = this._max;
			this.animate(this._scroller, "top:" + Math.round(offY) + "px", 200, "", this, function(){
				this.setOffY(offY);
				this.setTop(offY);
			});
			flag = true;
		}else if(this._v > 0){
			offY += this._v * 60;
			this._v -= 0.02;
			this.setTop(offY);
			this.setOffY(offY);
			if(this._v <= 0 || Math.abs(this._v) < 0.001){
				flag = true;
			}
		}else if(this._v < 0){
			offY += this._v * 60;
			this._v += 0.02;
			this.setTop(offY);
			this.setOffY(offY);
			if(this._v >= 0 || Math.abs(this._v) < 0.001){
				flag = true;
			}
		}
		if(flag){
			window.clearInterval(this._intervalID);
			this._intervalID = 0;
			this.hideScrollbar();
		}
	};
	/**
	 * [TODO]滚动结束时，如果没有自定义的scrollEnd事件，应该执行默认的惯性滚动行为
	 */
	this.onDefaultScrollEnd = function(ev){
		var ds = this._moveData[this._moveData.length - 1].s - this._moveData[0].s;
		if(-this._threshold < ds && ds < this._threshold){
			this.hideScrollbar();
			return true;
		}
		var sign = ds >= this._threshold ? 1 : -1;
		if(sign == 1 && this._offY >= this._max  //向下移动，超出范围限制
			|| sign == -1 && this._offY <= this._min){  //向上移动，超出范围限制
			var y = sign == 1 ? this._max : this._min;
			this.animate(this._scroller, "top:" + Math.round(y) + "px", 200, "", this, function(){
				this.setOffY(y);
				this.setTop(y);
			});
			this.hideScrollbar();
		}else{  //滚动惯性
			var vs = [];
			for(var i = 0, len = this._moveData.length - 1; i < len; i++){
				vs.push((this._moveData[i + 1].s - this._moveData[i].s) / (this._moveData[i + 1].t - this._moveData[i].t));
			}
			vs = this._removeAllItemFromArray(vs, NaN);
			vs = this._removeAllItemFromArray(vs, Infinity);
			vs = this._removeAllItemFromArray(vs, -Infinity);
			if(vs.length >= 5){
				var v_max = vs[0], v_min = vs[0];
				for(var i = 0, len = vs.length; i < len; i++){
					if(vs[i] < v_min){
						v_min = vs[i];
					}else if(vs[i] > v_max){
						v_max = vs[i];
					}
				}
				vs = this._removeAllItemFromArray(vs, v_max);
				vs = this._removeAllItemFromArray(vs, v_min);
				v_max = null;
				v_min = null;
			}
			var sum = 0;
			for(var i = 0, len = vs.length; i < len; i++){
				sum += vs[i];
			}
			var v = 0.5 * sum / vs.length;
			if(v > 1){
				v = 1;
			}else if(v < -1){
				v = -1;
			}
			this._v = v;
			v = null;
			sum = null;
			vs = null;
			var _this = this;
			this._intervalID = window.setInterval(function(){
				_this._scrollAnimation();
			}, 1000 / 60);
		}
		return true;
	};
	this.scrollTo = function(y, t){
		t = t || 500;
		this.animate(this._scroller, "top:" + Math.round(y) + "px", t, "", this, function(){
			this.setOffY(y);
			this.setTop(y);
		});
	};
	/*
	var hash = {};
	this.dump = function(str){
		return;
		var obj;
		if(str == "start0" && str in hash){
			hash = {};
		}
		if(!(str in hash)){
			obj = document.createElement("div");
			obj.style.border = "1px solid blue";
			obj.style.marginBottom = "1px";
			$E("log1").appendChild(obj);
			hash[str] = obj;
		}else{
			obj = hash[str];
		}
		var sb = [str];
		sb.push("this._viewportH=" + this._viewportH);
		sb.push("this._scrollerH=" + this._scrollerH);
		sb.push("this._top=" + this._top);
		sb.push("this._pageY=" + this._pageY);
		sb.push("this._offY=" + this._offY);
		sb.push("scroller.top=" + this._scroller.style.top);
		obj.innerHTML = sb.join(",");
		obj = null;
		console.log(sb.join(","));
	};
	*/
	/* *
	 * 匀加速运动基本公式：
	 * 1) s = v0t + 1/2at^2
	 */
	/*
	this.scrollToPage = function(){
		//var data = runtime._debugPane.showTable(this._moveData);
		//var sign = data.sign;
		var v0 = 2 * (this._top + this._viewportH - 200) / 200;  //sign * data.v;
		var t0 = new Date().getTime();  //时间
		var a = (0 - v0) / 200;  //加速度
		//console.log("v0=" + v0 + ",a=" + a);
		runtime.startTimer(10, this, function(){
			var t = new Date().getTime() - t0;
			var s = v0 * t + 0.5 * a * t * t;  //s = v0t+1/2at^2
			var y = Math.round(sign * s + this._top);
			this.dump("end-move");
			this.setTop(y);
			var vt = v0 + a * t;
			//console.log("s=" + s + ",y=" + this._top + ",vt=" + vt);
			if(vt <= 0){
				this._top = y;
				this.dump("end-end");
				//console.log(this._top);
			}else{
				return true;
			}
		});
	};
	*/
});